/**
 * This is the file that holds all of the image assets for the project.
 */

package edu.gatech.spacetraderteam3.view;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import edu.gatech.spacetraderteam3.debug.Debug;

/**
 * Asset class for the game's assets
 * 
 * @author TBW
 * @version 1.0
 */
public class Assets {// TODO: This entire class has to be rewritten so that we can
                     // gracefully catch image loading errors in the code. Dear god
                     // abstract classes would make thsi beautiful. Ergh.
    /**
     * Whether everything loaded properly or not.
     */
    private static boolean Loaded = true;

    /**
     * Interface for Image Assets
     * 
     * @author Randal
     * 
     */
    private interface ImageAsset {
        /**
         * @return the image associated with this asset
         */
        BufferedImage image();
    }

    /**
     * Interface for Assets withh multiple images
     * 
     * @author TBW
     * 
     */
    private interface MultiImageAsset {
        /**
         * @return an array of the images associated with this asset
         */
        BufferedImage[] images();
    }

    /**
     * @return whether all the images loaded properly
     */
    public static boolean didLoad() {
        return Loaded;
    }

    /**
     * Loads an image and returns it.
     * 
     * @param fileName
     *            the name of the file to load
     * @return the BufferedImage
     */
    private static BufferedImage loadImageGroup(String fileName) {
        BufferedImage image = null;
        try {
            image = ImageIO.read(new File(fileName));
        } catch (IOException e) { // $codepro.audit.disable logExceptions
            Debug.writeError("Error loading " + fileName);
            Loaded = false;
        }
        return image;
    }

    /**
     * Loads a list of images and puts them into an array.
     * 
     * @param assetPath
     *            the prefix of the file names
     * @param fileNames
     *            the file names
     * @return the array of BufferedImages
     */
    private static BufferedImage[] loadImages(String assetPath, String... fileNames) {
        final BufferedImage[] images = new BufferedImage[fileNames.length];
        for (int i = 0; i < fileNames.length; i++) {
            try {
                images[i] = ImageIO.read(new File(assetPath + fileNames[i] + ".png"));
            } catch (IOException e) { // $codepro.audit.disable logExceptions
                Debug.writeError("Error loading " + fileNames[i]);
                Loaded = false;
            }
        }
        return images;
    }

    /**
     * The CursorType enum.
     * 
     * @author Alexander Ikonomidis
     */
    public enum CursorType implements ImageAsset {
        MAIN("cursorPixel");

        /**
         * The file path for the cursor
         */
        private static final String ASSET_PATH = "GUI/Cursors/";

        /**
         * The cursor's image
         */
        private final BufferedImage image;

        /**
         * Constructs a CursorType from an image file.
         * 
         * @param fileName
         *            the file name of the cursor image
         */
        private CursorType(String fileName) {
            image = loadImageGroup(ASSET_PATH + fileName + ".png");
        }

        /**
         * @return the image associated with this asset
         */
        public BufferedImage image() {
            return image;
        }
    }

    /**
     * Surface enum
     * 
     * @author TBW
     * 
     */
    public enum Surface implements ImageAsset {
        TEST("PlanetTestGrid");

        /**
         * The file path for the surface
         */
        private static final String ASSET_PATH = "GUI/PlanetSurface/";

        /**
         * The image of the surface
         */
        private final BufferedImage image;

        /**
         * Constructs a Surface from the given file name
         * 
         * @param fileName
         *            the file name of the surface image
         */
        private Surface(String fileName) {
            image = loadImageGroup(ASSET_PATH + fileName + ".png");
        }

        /**
         * @return the image associated with this asset
         */
        public BufferedImage image() {
            return image;
        }
    }

    /**
     * Tile enum
     * 
     * @author TBW
     * 
     */
    public enum Tile implements ImageAsset {
        TEST("GridTile"),

        AMETHYST("AmethystTile"),
        CAMO("CamoTile"),
        COAL("CoalTile"),
        DARKSTONE("DarkStoneTile"),
        DESERT("DesertTile"),
        DIRT("DirtTile"),
        ELECTRIC("ElectricTile"),
        EMERALD("EmeraldTile"),
        GOLD("GoldTile"),
        GRASS("GrassTile"),
        LAVA("LavaTile"),
        LIGHT("LightTile"),
        LIMBO("LimboTile"),
        MARTIAN("MartianTile"),
        MIST("MistTile"),
        RAINBOW("RainbowTile"),
        RAINFOREST("RainforestTile"),
        RUBY("RubyTile"),
        SAND("SandTile"),
        SAPPHIRE("SapphireTile"),
        SEA("SeaTile"),
        SLATE("SlateTile"),
        SMOKE("SmokeTile"),
        SNOW("SnowTile"),
        STEAM("SteamPunkTile"),
        STONE("StoneTile"),
        WOOD("WoodTile");

        /**
         * The Filepath for the Planet's background
         */
        private static final String ASSET_PATH = "GUI/PlanetSurface/PlanetTiles/";

        /**
         * The image of the planet's background tiles
         */
        private final BufferedImage image;

        /**
         * Constructs a tile from a given image file
         * 
         * @param fileName
         *            the name of the image file
         */
        private Tile(String fileName) {
            image = loadImageGroup(ASSET_PATH + fileName + ".png");
        }

        /**
         * @return the image associated with this asset
         */
        public BufferedImage image() {
            return image;
        }
    }

    /**
     * PlanetIcon enum
     * 
     * @author TBW
     * 
     */
    public enum PlanetIcon implements ImageAsset {
        TEST("test"),
        BLUE("BluePlanet"),
        ORANGE_RINGS("OrangePlanet"),
        BROWN("BrownPlanet"),
        PURPLE("PurplePlanet"),
        RED_GREEN("RedGreenPlanet");

        /**
         * The file path for the planet icons
         */
        private static final String ASSET_PATH = "CelestialBodies/PlanetIcons/";

        /**
         * The image of the planet
         */
        private final BufferedImage image;

        /**
         * Constructs a Planet icon from the given image file
         * 
         * @param fileName
         *            the name of the image file
         */
        private PlanetIcon(String fileName) {
            image = loadImageGroup(ASSET_PATH + fileName + ".png");
        }

        /**
         * @return the image associated with this asset
         */
        public BufferedImage image() {
            return image;
        }
    }

    /**
     * MoonIcon enum
     * 
     * @author TBW
     * 
     */
    public enum MoonIcon implements ImageAsset {
        LUNA("GreyMoon");

        /**
         * The filepath of the moon
         */
        private static final String ASSET_PATH = "CelestialBodies/PlanetIcons/";

        /**
         * The image of the moon
         */
        private final BufferedImage image;

        /**
         * Constructor for MoonIcon
         * 
         * @param fileName
         *            Name of the Moonicon image file
         */
        private MoonIcon(String fileName) {
            image = loadImageGroup(ASSET_PATH + fileName + ".png");
        }

        /**
         * Getter for the Moonicon image
         * 
         * @return The image
         */
        public BufferedImage image() {
            return image;
        }
    }

    /**
     * SunIcon asset enum
     * 
     * @author TBW
     */
    public enum SunIcon implements ImageAsset {
        SOL("Sol") {
            public void paint(Graphics2D g, double time, int diameter, int centerX,
                    int centerY) {
                wobblePaint(g, time, diameter, centerX, centerY);
            }
        },
        NEUTRINO("Neutrino") {
            public void paint(Graphics2D g, double time, int diameter, int centerX,
                    int centerY) {
                pulsePaint(g, time, diameter, centerX, centerY);
            }
        };

        /**
         * The filepath of the sun
         */
        private static final String ASSET_PATH = "CelestialBodies/SunIcons/";

        /**
         * The image of the sun
         */
        private final BufferedImage image;

        /**
         * Constructor that loads the SunIcon image asset
         * 
         * @param fileName
         *            Name of the image file to load
         */
        private SunIcon(String fileName) {
            image = loadImageGroup(ASSET_PATH + fileName + ".png");
        }

        /**
         * Paints the SunIcon
         * 
         * @param g
         *            Graphics component to paint on
         * @param time
         *            Time used in Wobble effect
         * @param diameter
         *            Diameter of the Sun
         * @param centerX
         *            X value of the center of the Sun
         * @param centerY
         *            Y value of the center of the Sun
         */
        public abstract void paint(Graphics2D g, double time, int diameter, int centerX,
                int centerY);

        /**
         * Draws sun with the wobble effect
         * 
         * @param g
         *            Graphics component to paint on
         * @param time
         *            Time used in wobble effect calculation
         * @param diameter
         *            Diameter of the Sun
         * @param centerX
         *            X value of the center of the Sun
         * @param centerY
         *            Y value of the center of the Sun
         */
        public void wobblePaint(Graphics2D g, double time, int diameter, int centerX,
                int centerY) {
            final BufferedImage sunBuff = new BufferedImage(diameter, diameter,
                    BufferedImage.TYPE_INT_ARGB);
            sunBuff.getGraphics().drawImage(image, 0, 0, diameter, diameter, null);
            g.drawImage(ImageFilters.wobble(sunBuff, time, 1, 0), centerX - diameter / 2,
                        centerY - diameter / 2, diameter, diameter, null);
        }

        /**
         * Draws sun with pulse effect
         * 
         * @param g
         *            Graphics component to paint on
         * @param time
         *            Time used in calculation of pulse effect
         * @param diameter
         *            Diameter of the sun
         * @param centerX
         *            X value of the center of the Sun
         * @param centerY
         *            Y value of the center of the Sun
         */
        public void pulsePaint(Graphics2D g, double time, int diameter, int centerX,
                int centerY) {
            final BufferedImage sunBuff = new BufferedImage(diameter, diameter,
                    BufferedImage.TYPE_INT_ARGB);
            sunBuff.getGraphics().drawImage(image, 0, 0, diameter, diameter, null);
            g.drawImage(ImageFilters.pulse(sunBuff, time), centerX - diameter / 2,
                        centerY - diameter / 2, diameter, diameter, null);
        }

        /**
         * Getter for the SunIcon image
         * 
         * @return The Image
         */
        public BufferedImage image() {
            return image;
        }
    }

    /**
     * PlanetTexture enum
     * 
     * @author TBW
     * 
     */
    public enum PlanetTexture implements ImageAsset {
        PLANET_SHADOW_MASK("ShadowTexture"),
        ATMOSPHERE_MASK("AtmosphereTexture"),

        ALIEN("AlienMarkingsTexture"),
        BARREN("BarrenTexture"),
        BLUE("BlueAtmosphereTexture"),
        CRATER("CraterTexture"),
        DIAMOND("DiamondTexture"),
        ELECTRIC("ElectricPlanet"),
        GREEN("GreenAtmosphereTexture"),
        JUNGLE("JungleTexture"),
        LUSH("LushTexture"),
        MARBLE("MarbleTexture"),
        METAL("MetalTexture"),
        MINT("MintTexture"),
        MOLTEN("MoltenTexture"),
        ORANGE("OrangeTexture"),
        RED("RedAtmosphereTexture"),
        ROUGHSMOOTH("RoughSmoothTexture"),
        SEA("SeaTexture"),
        SHINE("ShineTexture"),
        SKY("SkyBlueTexture"),
        YELLOW("YellowAtmosphereTexture");

        /**
         * The filepath for the planet textures
         */
        private static final String ASSET_PATH = "CelestialBodies/PlanetTextures/";

        /**
         * The image of the planet texture
         */
        private final BufferedImage image;

        /**
         * Loads planet texture
         * 
         * @param fileName
         *            Name of the texture to load
         */
        private PlanetTexture(String fileName) {
            image = loadImageGroup(ASSET_PATH + fileName + ".png");
        }

        /**
         * Getter for the PlanetTexture image
         * 
         * @return PlanetTexture image
         */
        public BufferedImage image() {
            return image;
        }

        /**
         * Randomly selects a PlanetTexture
         * 
         * @return Random PlanetTexture
         */
        public static PlanetTexture random() {
            return values()[(int) (Math.random() * (values().length - 2)) + 2];
        }
    }

    /**
     * ButtonType enum
     * 
     * @author TBW
     * 
     */
    public enum ButtonType implements MultiImageAsset {
        BASIC("button"),
        CARGO("CargoTab"),
        MAP("MapTab"),
        MY_SHIP("MyShipTab"),
        NEWS("NewsTab"),
        SPINNER_BLUE_MINUS("SpinnerBlueMinus"),
        SPINNER_BLUE_PLUS("SpinnerBluePlus"),
        SPINNER_GREEN_MINUS("SpinnerGreenMinus"),
        SPINNER_GREEN_PLUS("SpinnerGreenPlus"),
        SPINNER_GREY_MINUS("SpinnerGreyMinus"),
        SPINNER_GREY_PLUS("SpinnerGreyPlus"),
        SLIDER("SliderButton"),
        MENU_ACCEPT("button"),
        TITLE_CONTINUE("titleContinue"),
        TITLE_NEW("titleNew");

        /**
         * The filepath for the buttons
         */
        private static final String ASSET_PATH = "GUI/Buttons/";

        /**
         * The images of the buttons
         */
        private final BufferedImage[] images;

        /**
         * Load's image asset
         * 
         * @param fileName
         *            Name of asset to load
         */
        private ButtonType(String fileName) {
            images = loadImages(ASSET_PATH, fileName, fileName + "Down");
        }

        /**
         * Getter for ButtonType image
         * 
         * @return Image
         */
        public BufferedImage[] images() {
            return images;
        }
    }

    /**
     * Window Skin enum
     * 
     * @author TBW
     * 
     */
    public enum WindowSkin implements MultiImageAsset {
        // corner, point, side, tile
        TEST("corner", "point", "side", "tile"),
        CARBON("carbonCorner", "carbonPoint", "carbonSide", "carbonTile"),
        SPACE("spaceCorner", "spacePoint", "spaceSide", "spaceTile");

        /**
         * The filepath of the window skins
         */
        private static final String ASSET_PATH = "GUI/Windows/";

        /**
         * The images for the skins
         */
        private final BufferedImage[] images;

        /**
         * Loads Window Skin asset
         * 
         * @param fileNames
         *            Asset to load
         */
        private WindowSkin(String... fileNames) {
            images = loadImages(ASSET_PATH, fileNames);
        }

        /**
         * Getter for the Window skin array of elements
         * 
         * @return Skin elements
         */
        public BufferedImage[] images() {
            return images;
        }

        /**
         * Getter for the window corner asset
         * 
         * @return window corner asset
         */
        public BufferedImage corner() {
            return images[0];
        }

        /**
         * Getter for the window point asset
         * 
         * @return Window point image asset
         */
        public BufferedImage point() {
            return images[1];
        }

        /**
         * Getter for the window side asset
         * 
         * @return Window side asset
         */
        public BufferedImage side() {
            return images[2];
        }

        /**
         * Getter for the window tile asset
         * 
         * @return Window tile asset
         */
        public BufferedImage tile() {
            return images[3];
        }
    }

    /**
     * Misc Asset enum
     * 
     * @author TBW
     * 
     */
    public enum MiscImage implements ImageAsset { // This takes a file path because it's
                                                  // not guaranteed a particular folder
        GALAXY("CelestialBodies/Galaxy.png"),
        GALAXY_BLURRED("CelestialBodies/GalaxyBlurred.png"),
        SPINNER_BLUE_TEXT_AREA("GUI/Misc/SpinnerBlueText.png"),
        SPINNER_GREEN_TEXT_AREA("GUI/Misc/SpinnerGreenText.png"),
        SLIDER_END("GUI/Misc/sliderEnd.png"),
        SLIDER_REPEAT("GUI/Misc/sliderRepeat.png"),
        TITLE("GUI/Misc/titleScreen.png"),
        SHIP_ICON("GUI/Misc/ShipIcon.png"),
        PIRATE_ICON("GUI/Misc/PirateShip.png"),
        POLICE_ICON("GUI/Misc/PoliceShip.png");

        /**
         * The image of the misc
         */
        private final BufferedImage image;

        /**
         * Loads asset with given file path
         * 
         * @param filePath
         *            File path of the asset
         */
        private MiscImage(String filePath) {
            image = loadImageGroup(filePath);
        }

        /**
         * Getter for the misc image asset
         * 
         * @return Misc asset
         */
        public BufferedImage image() {
            return image;
        }
    }

    /**
     * To string method that returns "Asset."
     * 
     * @return "Asset."
     */
    public String toString() {
        return "Asset.";
    }
}
